package com.sap.sap_mangers.service.Impl;

import com.sap.sap_mangers.Vo.ShareVo.ApprovedShareRecord;
import com.sap.sap_mangers.Vo.ShareVo.SapShareVo;
import com.sap.sap_mangers.Vo.ShareVo.ShareTypeWithData;
import com.sap.sap_mangers.dto.share.ModifyFile;
import com.sap.sap_mangers.dto.share.UploadFile;
import com.sap.sap_mangers.dto.user.NoticeDto;
import com.sap.sap_mangers.email.IMailService;
import com.sap.sap_mangers.mapper.ShareMapper;
import com.sap.sap_mangers.pojo.SapShare;
import com.sap.sap_mangers.pojo.SapShareType;
import com.sap.sap_mangers.pojo.SapShareVersion;
import com.sap.sap_mangers.pojo.User;
import com.sap.sap_mangers.service.CacheService;
import com.sap.sap_mangers.service.ShareService;
import com.sap.sap_mangers.service.UserService;
import com.sap.sap_mangers.until.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 阿东
 * @date 2022/9/12 [0:31]
 */
@Service
public class ShareServiceImpl implements ShareService {
    @Autowired
    private ShareMapper shareMapper;
    @Autowired
    private CosUntil cosUntil;
    @Autowired
    private CacheService cacheService;
    @Autowired
    private IMailService imailService;
    @Autowired
    private UserService userService;


    @Override
    public SimpleJson uploadFile(UploadFile uploadFile) {
        try {
            String cosUrl = cosUntil.getCosUrl(uploadFile.getFile(), "share/(" + new Timestamp(System.currentTimeMillis()) + ")" + JwtUtil.getUserForToken() + "[" + cacheService.getRealNameCache(cacheService.getRealNameCacheMap(), JwtUtil.getUserForToken()) + "]" + "/" + uploadFile.getFile().getOriginalFilename());
            uploadFile.setFileUrl(cosUrl);
        } catch (IOException e) {
            e.printStackTrace();
            return new SimpleJson(1, "文件上传出错");
        }
        try {
            executeUploadFile(uploadFile);
        } catch (Exception e) {
            e.printStackTrace();
            return new SimpleJson(1, "sql执行出错");
        }
        return SimpleJson.SUCCESS;
    }

    /**
     * 执行上传资料操作及发送邮件
     *
     * @param uploadFile 资料上传信息
     */
    private void executeUploadFile(UploadFile uploadFile) {
        uploadFile.setUsername(JwtUtil.getUserForToken());
        uploadFile.setName(cacheService.getRealNameCache(cacheService.getRealNameCacheMap(), JwtUtil.getUserForToken()));
        uploadFile.setCreateTime(new Timestamp(System.currentTimeMillis()));
        uploadFile.setTip(FileTipUntil.getTip(1));
        shareMapper.uploadFile(uploadFile);
        User presidentUserInfo = userService.getPresidentUserInfo();
        imailService.sendHtmlMail(presidentUserInfo.getQq() + "@qq.com",
                "上传资料需要审核",
                EmailUntil.emailForPassUploadFileToManager(uploadFile.getName(), uploadFile.getTopic(), new Timestamp(System.currentTimeMillis()).toString()));
        userService.sendNotice(new NoticeDto(presidentUserInfo.getUsername(), "请审核上传资料", null));
    }

    @Override
    public SimpleJson addFileUrl(UploadFile uploadFile) {
        try {
            executeUploadFile(uploadFile);
        } catch (Exception e) {
            e.printStackTrace();
            return new SimpleJson(1, "sql执行出错");
        }
        return SimpleJson.SUCCESS;
    }

    @Override
    public List<SapShareType> getSapShareType() {
        return shareMapper.getSapShareType();
    }

    @Override
    public SapShareType getSapShareTypeById(Integer shareTypeId) {
        return shareMapper.getSapShareTypeById(shareTypeId);
    }

    @Override
    public List<SapShareVo> getSapShareThatNotNotBeAudited() {
        return shareMapper.getSapShareThatNotNotBeAudited();
    }

    @Override
    public List<SapShareVo> getAllSapShare() {
        return shareMapper.getAllSapShare();
    }

    @Override
    public void updateShared(Integer id, Integer value) {
        shareMapper.updateShared(id, value);
    }

    @Override
    public List<SapShare> getSapShare(String username, Integer approval) {
        return shareMapper.getSapShare(username, approval);
    }

    @Override
    public List<SapShareVo> getSapShareForUser(String username) {
        return shareMapper.getSapShareForUser(username);
    }

    @Override
    public SimpleJson deleteFile(Integer id) {
        List<SapShareVersion> versions = shareMapper.getSapShareVersionByOldIdWithCondition(id, 0);
        if (versions != null && !versions.isEmpty()) {
            return new SimpleJson(1, "存在未经审核的修改版本，暂时无法删除；如果提交的修改被审核通过此数据将自动过期");
        }
        //异常在外面捕获了
        shareMapper.deleteFile(id);
        return SimpleJson.SUCCESS;
    }

    @Override
    public void updateDownloadFile(Integer id) {
        try {
            shareMapper.updateDownloadFile(id);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public SapShare getShareMessageById(Integer id) {
        try {
            return shareMapper.getShareMessageById(id);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public ApprovedShareRecord getApprovedShareRecord() {
        //可共享的资料(上传)总记录
        ApprovedShareRecord result = new ApprovedShareRecord();
        //获取以纯网址形式分享的资料 (按资料类型id从小到大排序) 并分类包装
        List<SapShareVo> shareWhichHaveUrl = shareMapper.getApprovedShareWhichHaveUrl();
        for (SapShareVo sapShareVo : shareWhichHaveUrl) {
            sapShareVo.setHeader(cacheService.getHeaderCache(cacheService.getHeaderCacheMap(),sapShareVo.getShareUsername()));
        }
        result.setDataSharedInTheFormOfUrl(createShareTypeWithDataList(shareWhichHaveUrl));
        //以对象存储文件(地址)形式分享的资料 (按资料类型id从小到大排序) 并分类包装
        List<SapShareVo> shareWhichHaveCos = shareMapper.getApprovedShareWhichHaveCos();
        for (SapShareVo shareWhichHaveCo : shareWhichHaveCos) {
            shareWhichHaveCo.setHeader(cacheService.getHeaderCache(cacheService.getHeaderCacheMap(),shareWhichHaveCo.getShareUsername()));
        }
        result.setDataSharedInTheFormOfCos(createShareTypeWithDataList(shareWhichHaveCos));
        return result;
    }

    /**
     * 工具方法 - 将输入的共享资料记录按资料类型分类包装
     * <p>
     * 注意: 请保证输入的参数根据资料类型ID从小到大排序，否则无法达到效果！！！
     *
     * @param shares 根据资料类型ID从小到大排序的共享资料记录(列表)
     * @return 按资料类型分类包装的结果
     */
    private List<ShareTypeWithData> createShareTypeWithDataList(List<SapShareVo> shares) {
        int idx = 0;
        int len = shares.size();
        SapShareVo sapShareVo = idx < len ? shares.get(idx) : null;
        //获取资料类型
        List<SapShareType> types = shareMapper.getSapShareType();
        List<ShareTypeWithData> list = new ArrayList<>();
        //遍历处理，应参数中的数据按资料类型ID从小到大排序，所以遇到类型不匹配的就进入下一个类型查找 (不需要n*m的查找)
        for (SapShareType sapShareType : types) {
            String type = sapShareType.getShareTypeContext();
            List<SapShareVo> sharedData = new ArrayList<>();
            ShareTypeWithData shareTypeWithData = new ShareTypeWithData(type, sharedData);
            while (idx < len && sapShareVo.getShareTypeContext().equals(type)) {
                sharedData.add(sapShareVo);
                if (++idx < len) {
                    sapShareVo = shares.get(idx);
                }
            }
            list.add(shareTypeWithData);
        }
        return list;
    }

    /**
     * 执行修改资料操作及发送邮件
     * 有两次插入数据操作，支持事务回滚
     *
     * @param modifyFile 资料修改信息
     */
    @Transactional(rollbackFor = Exception.class)
    void executeModifyFile(ModifyFile modifyFile) {
        //添加待审核数据到资料上传记录表
        modifyFile.setUsername(JwtUtil.getUserForToken());
        modifyFile.setName(cacheService.getRealNameCache(cacheService.getRealNameCacheMap(), JwtUtil.getUserForToken()));
        modifyFile.setCreateTime(new Timestamp(System.currentTimeMillis()));
        modifyFile.setTip(FileTipUntil.getTip(1));
        shareMapper.modifyFile(modifyFile);
        //添加版本更替记录(审核通过才生效)
        shareMapper.addNewVersionRecord(modifyFile.getShareId(), modifyFile.getOldShareVersion());
        //向会长发消息
        User presidentUserInfo = userService.getPresidentUserInfo();
        imailService.sendHtmlMail(presidentUserInfo.getQq() + "@qq.com",
                "修改资料等待审核",
                EmailUntil.emailForPassModifyFileToManager(modifyFile.getName(), modifyFile.getTopic(), new Timestamp(System.currentTimeMillis()).toString()));
        userService.sendNotice(new NoticeDto(presidentUserInfo.getUsername(), "请审核修改资料", null));
    }

    @Override
    public SimpleJson modifyFile(ModifyFile modifyFile) {
        try {
            String cosUrl = cosUntil.getCosUrl(modifyFile.getFile(), "share/(" + new Timestamp(System.currentTimeMillis()) + ")" + JwtUtil.getUserForToken() + "[" + cacheService.getRealNameCache(cacheService.getRealNameCacheMap(), JwtUtil.getUserForToken()) + "]" + "/" + modifyFile.getFile().getOriginalFilename());
            modifyFile.setFileUrl(cosUrl);
        } catch (IOException e) {
            e.printStackTrace();
            return new SimpleJson(4, "文件上传出错");
        }
        try {
            executeModifyFile(modifyFile);
        } catch (Exception e) {
            e.printStackTrace();
            return new SimpleJson(5, "sql执行出错");
        }
        return SimpleJson.SUCCESS;
    }

    @Override
    public SimpleJson addFileUrlWhenModify(ModifyFile modifyFile) {
        try {
            executeModifyFile(modifyFile);
        } catch (Exception e) {
            e.printStackTrace();
            return new SimpleJson(5, "sql执行出错");
        }
        return SimpleJson.SUCCESS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SimpleJson failedToPassTheAudit(Integer shareId, String reason) {
        //判断操作人是否是管理员
        String userForToken = JwtUtil.getUserForToken();
        User managerUser = userService.getUserByUserName(userForToken);
        if (managerUser == null) {
            return new SimpleJson(1, "权限不足");
        } else if (managerUser.getRole() < 0 && managerUser.getRole() > 9) {
            return new SimpleJson(1, "权限不足");
        }
        //判断参数(资料分享ID)对应的数据是否存在
        SapShare sapShare = shareMapper.getShareMessageById(shareId);
        if (sapShare == null) {
            return new SimpleJson(2, "编号不存在");
        }
        //判断数据目前的状态是不是未审批
        if (sapShare.getShareApproval() != 0) {
            return new SimpleJson(3, "分享记录已不在未审核状态");
        }
        //将审核数据填入记录中
        Timestamp now = new Timestamp(System.currentTimeMillis());
        String managerUsername = managerUser.getUsername();
        String managerName = cacheService.getRealNameCache(cacheService.getRealNameCacheMap(), managerUsername);
        //不再主动捕获异常，改为事务处理
        shareMapper.updateShareWhenAudit(shareId, 2, now, managerUsername, managerName);
        //增加逻辑: 如果在版本记录表中有相应数据，将替换标识改为没被替换(2)
        shareMapper.updateSapShareVersionIfUpdateByNewVersion(shareId, 2);
        //发送邮件给提供资料的用户，邮件将包含驳回的原因
        String username = sapShare.getShareUsername();
        String name = sapShare.getShareName();
        User user = userService.getUserByUserName(username);
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dataString = df.format(sapShare.getShareCreateTime());
        String notice = "[审核驳回] 你分享的资料" + sapShare.getShareTopic() + "(对应资料分享ID:" + shareId + ")已被管理员驳回，原因为:" + reason;
        String email = EmailUntil.emailForPassUploadFile(name, sapShare.getShareTopic(), dataString, reason);
        userService.sendNoticeAuto(new NoticeDto(username, notice, null));
        try {
            imailService.sendHtmlMail(user.getQq() + "@qq.com", "分享资料审核驳回", email);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return SimpleJson.SUCCESS;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SimpleJson passTheAudit(Integer shareId) {
        //判断管理员权限
        String userForToken = JwtUtil.getUserForToken();
        User managerUser = userService.getUserByUserName(userForToken);
        if (managerUser == null) {
            return new SimpleJson(1, "权限不足");
        }
        if (managerUser.getRole() < 0 && managerUser.getRole() > 9) {
            return new SimpleJson(1, "权限不足");
        }
        //查找资料分享记录
        SapShare sapShare = shareMapper.getShareMessageById(shareId);
        if (sapShare == null) {
            return new SimpleJson(2, "编号不存在");
        } else if (sapShare.getShareApproval() != 0) {
            return new SimpleJson(3, "分享记录已不在未审核状态");
        }
        //将审核数据填入记录中
        Timestamp now = new Timestamp(System.currentTimeMillis());
        String managerUsername = managerUser.getUsername();
        String managerName = cacheService.getRealNameCache(cacheService.getRealNameCacheMap(), managerUsername);
        //如果sql异常就让他抛出去，这个方法要操作多个数据库，出问题了直接回滚
        shareMapper.updateShareWhenAudit(shareId, 1, now, managerUsername, managerName);
        //查找是否有对应的旧版本数据 (在资料修改版本记录表)
        SapShareVersion version = shareMapper.getSapShareVersionByNewId(shareId);
        if (version != null) {
            Integer oldShareId = version.getOldVersionShareId();
            //检查旧版本是否仍然是通过状态
            SapShare oldShare = shareMapper.getShareMessageById(oldShareId);
            if (oldShare != null && oldShare.getShareApproval() == 1) {
                //有旧版本就将旧版本设置过期
                shareMapper.makeOldShareVersionOverdue(oldShareId);
                //将资料修改版本记录表 对应数据中的 替换标识改为1
                shareMapper.updateSapShareVersionIfUpdateByNewVersion(shareId, 1);
                //继承旧版本的下载/访问量数据
                shareMapper.inheritDownloadsFromOlderVersion(shareId, oldShareId);
            } else {
                return new SimpleJson(6, "分享资料的旧版本已不在通过状态，可能因为对原资料提交了多个修改版本且其中一个已被审核通过");
            }
        }
        //发送邮件和通知给提供资料的用户
        String username = sapShare.getShareUsername();
        String name = sapShare.getShareName();
        User user = userService.getUserByUserName(username);
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dataString = df.format(sapShare.getShareCreateTime());
        String notice = "[审核通过] 你分享的资料" + sapShare.getShareTopic() + "(对应资料分享ID:" + shareId + ")已经审核通过";
        String email = EmailUntil.emailForPassUploadFile(name, sapShare.getShareTopic(), dataString);
        userService.sendNoticeAuto(new NoticeDto(username, notice, null));
        try {
            imailService.sendHtmlMail(user.getQq() + "@qq.com", "分享资料审核通过", email);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return SimpleJson.SUCCESS;
    }

    @Override
    public List<SapShareVo> getApprovalTopTen() {
        List<SapShareVo> approvalTopTen = shareMapper.getApprovalTopTen();
        for (SapShareVo sapShareVo : approvalTopTen) {
            sapShareVo.setHeader(cacheService.getHeaderCache(cacheService.getHeaderCacheMap(),sapShareVo.getShareUsername()));
        }
        return approvalTopTen;
    }
}
